# @Time    : 2024/3/2 20:17
# @Author  : 🍁
# @File    : price.py
# @Software: PyCharm
import datetime
import json

from django.views import View
from django.shortcuts import render, redirect, HttpResponse
from django import http
from django_redis import get_redis_connection
from django.conf import settings

from urllib.parse import parse_qs
from web import models
from web.utils.scrypty import uid

from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA256
from base64 import decodebytes, encodebytes
from web.utils.alipay import AliPay


class PriceView(View):
    def get(self, request):
        price_list = models.PriceClassify.objects.filter(price__isnull=False)
        return render(request, "price.html", {"price_list": price_list})


class PriceListView(View):
    def get(self, request, policy_id):
        # 判断价格策略是否存在
        policy_object = models.PriceClassify.objects.filter(id=policy_id, price__isnull=False).first()
        if not policy_object:
            return redirect("price")
        # 获取购买数量
        number = request.GET.get("number", "")
        if not number or not number.isdecimal() or int(number) == 0:
            return redirect("price")

        # 计算出原始价格
        price = policy_object.price * int(number)
        # 拿到当前用户的购买套餐
        balance = 0
        user_policy = request.tartec.price_classify.id
        classify = None
        if user_policy != 1:
            # 折扣金额 = 之前没有过期的套餐进行折扣
            # 价格 = 原始价格 - 折扣的钱
            classify = models.TransactionRecord.objects.filter(user=request.tartec.user,
                                                               price_classify__classify=user_policy).order_by("-id")
            days = classify.end_date - classify.start_date
            end_days = classify.end_date - datetime.datetime.now()

            if end_days > 0:
                if days.days == end_days.days:
                    balance = classify.price / (end_days.days * days.days - 1)
                else:
                    balance = classify.price / (end_days.days * days.days - 1)
            if balance >= price:
                return redirect("price")

        content = {
            "id": policy_object.id,
            "balance": round(balance, 2),
            "origin_price": price,
            "price": price - round(balance, 2),
            "number": number,
        }
        conn = get_redis_connection("payment")
        key = "payment_{}".format(request.tartec.user.mobile)
        conn.setex(key, 60 * 30, json.dumps(content))
        content["policy_object"] = policy_object
        content["transaction"] = classify

        return render(request, "payment.html", content)


class PayView(View):
    def get(self, request):
        conn = get_redis_connection("payment")
        context_string = conn.get("payment_{}".format(request.tartec.user.mobile))
        if not context_string:
            return redirect("price")
        context = json.loads(context_string)
        total_price = context["price"]
        # 在数据库当中创建交易记录
        order_id = uid(request.tartec.user.mobile)
        models.TransactionRecord.objects.create(
            state=1,
            order=order_id,
            user=request.tartec.user,
            price_classify_id=context["id"],
            count=context["number"],
            price=total_price
        )

        # 2. 跳转到支付去支付
        #    - 根据申请的支付的信息 + 支付宝的文档 => 跳转链接
        #    - 生成一个支付的链接
        #    - 跳转到这个链接
        # 构造字典

        # params = {
        #     'app_id': "9021000134694044",
        #     'method': 'alipay.trade.page.pay',
        #     'format': 'JSON',
        #     'return_url': "http://127.0.0.1:8001/pay/notify/",
        #     'notify_url': "http://127.0.0.1:8001/pay/notify/",
        #     'charset': 'utf-8',
        #     'sign_type': 'RSA2',
        #     'timestamp': datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
        #     'version': '1.0',
        #     'biz_content': json.dumps({
        #         'out_trade_no': order_id,
        #         'product_code': 'FAST_INSTANT_TRADE_PAY',
        #         'total_amount': total_price,
        #         'subject': "tracer payment"
        #     }, separators=(',', ':'))
        # }
        #
        # # 获取待签名的字符串
        # unsigned_string = "&".join(["{0}={1}".format(k, params[k]) for k in sorted(params)])
        #
        # # 签名 SHA256WithRSA(对应sign_type为RSA2)
        #
        # # SHA256WithRSA + 应用私钥 对待签名的字符串 进行签名
        # private_key = RSA.importKey(open("filter/应用私钥RSA2048-敏感数据，请妥善保管.txt").read())
        # signer = PKCS1_v1_5.new(private_key)
        # signature = signer.sign(SHA256.new(unsigned_string.encode('utf-8')))
        #
        # # 对签名之后的执行进行base64 编码，转换为字符串
        # sign_string = encodebytes(signature).decode("utf8").replace('\n', '')
        #
        # # 把生成的签名赋值给sign参数，拼接到请求参数中。
        #
        # from urllib.parse import quote_plus
        # result = "&".join(["{0}={1}".format(k, quote_plus(params[k])) for k in sorted(params)])
        # result = result + "&sign=" + quote_plus(sign_string)
        #
        # gateway = "https://openapi-sandbox.dl.alipaydev.com/gateway.do"
        # ali_pay_url = "{}?{}".format(gateway, result)
        ali_pay = AliPay(
            appid=settings.ALI_APPID,
            app_notify_url=settings.ALI_NOTIFY_URL,
            return_url=settings.ALI_RETURN_URL,
            app_private_key_path=settings.ALI_PRI_FILE,
            alipay_public_key_path=settings.ALI_PUB_FILE
        )
        query_params = ali_pay.direct_pay(
            subject="trace rpayment",  # 商品简单描述
            out_trade_no=order_id,  # 商户订单号
            total_amount=total_price
        )
        ali_pay_url = "{}?{}".format(settings.ALI_GATEWAY, query_params)
        return redirect(ali_pay_url)


class PayNotifyView(View):
    ali_pay = AliPay(
        appid=settings.ALI_APPID,
        app_notify_url=settings.ALI_NOTIFY_URL,
        return_url=settings.ALI_RETURN_URL,
        app_private_key_path=settings.ALI_PRI_FILE,
        alipay_public_key_path=settings.ALI_PUB_FILE
    )

    def get(self, request):
        # 只做跳转，判断是否支付成功了，不做订单的状态更新。没有公网ip 现在get请求里面保存一下
        # 支付吧会讲订单号返回：获取订单ID，然后根据订单ID做状态更新 + 认证。
        # 支付宝公钥对支付给我返回的数据request.GET 进行检查，通过则表示这是支付宝返还的接口。
        # 拿到订单号进行验证是否是支付宝传进来的参数
        params = request.GET.dict()
        sign = params.pop("sign", None)
        status = self.ali_pay.verify(params, sign)
        print(params)
        print(status)
        if status:
            # 保存一下订单
            date_time_now = datetime.datetime.now()
            order_id = params["out_trade_no"]
            _object = models.TransactionRecord.objects.filter(order=order_id).first()
            _object.state = 2
            _object.start_date = date_time_now
            _object.end_date = date_time_now + datetime.timedelta(days=_object.count * 365)
            request.tartec.user.price_classify = _object.id
            request.tartec.user.save()
            _object.save()
            return http.HttpResponse("支付成功")
        else:
            return http.HttpResponse("支付失败")

    def post(self, request):
        # post 请求需要更改配置中的ip为公网id，才能发送一下请求，所以保存订单现在先写道get请求中
        body = request.body
        post_data = parse_qs(body)
        post_dict = {}
        for k, v in post_data.items():
            post_dict[k] = v

        sign = post_dict.pop("sign", None)
        status = self.ali_pay.verify(post_dict, sign)
        if status:
            # 保存订单
            date_time_now = datetime.datetime.now()
            order_id = post_dict["out_trade_no"]
            _object = models.TransactionRecord.objects.filter(order=order_id).first()
            _object.state = 2
            _object.start_date = date_time_now
            _object.end_date = date_time_now + datetime.timedelta(days=_object.count * 365)
            _object.save()
            return http.HttpResponse("success")
        return http.HttpResponse("error")
